package com.moodbox.server.user.service.impl;

import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.moodbox.server.common.enums.UserRoleEnum;
import com.moodbox.server.common.exception.AuthorizationException;
import com.moodbox.server.user.dto.UserProfileDTO;
import com.moodbox.server.user.dto.WxLoginDTO;
import com.moodbox.server.user.entity.User;
import com.moodbox.server.user.mapper.UserMapper;
import com.moodbox.server.user.service.UserService;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.security.Key;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;
import java.util.Map;

@Slf4j
@Service
@RequiredArgsConstructor
public class UserServiceImpl implements UserService {

    private final UserMapper userMapper;
    private final Key jwtSecretKey;

    @Value("${wx.app-id}")
    private String wxAppId;

    @Value("${wx.app-secret}")
    private String wxAppSecret;

    @Override
    public User getUserById(String userId) {
        if (StrUtil.isBlank(userId)) {
            return null;
        }
        return userMapper.selectById(userId);
    }

    @Override
    public User getUserByWxOpenId(String wxOpenId) {
        if (StrUtil.isBlank(wxOpenId)) {
            return null;
        }
        return userMapper.selectByWxOpenId(wxOpenId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public User wxLogin(WxLoginDTO wxLoginDTO) {
        // 调用微信登录接口获取OpenId和SessionKey
        String url = String.format(
            "https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code", 
            wxAppId, wxAppSecret, wxLoginDTO.getCode()
        );
        
        String result = HttpUtil.get(url);
        log.info("微信登录返回结果：{}", result);
        
        Map<String, Object> resultMap = JSONUtil.parseObj(result);
        String openId = (String) resultMap.get("openid");
        String sessionKey = (String) resultMap.get("session_key");

        // 查找或创建用户
        User user = getUserByWxOpenId(openId);
        if (user == null) {
            user = new User()
                .setWxOpenId(openId)
                .setCreateTime(LocalDateTime.now())
                .setUpdateTime(LocalDateTime.now());
        }

        // 更新用户信息
        user.setNickname(wxLoginDTO.getNickname())
            .setAvatarUrl(wxLoginDTO.getAvatarUrl())
            .setUpdateTime(LocalDateTime.now());

        // 保存或更新用户
        if (user.getId() == null) {
            createUser(user);
        } else {
            updateUser(user);
        }

        return user;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public User createUser(User user) {
        if (user == null) {
            throw new IllegalArgumentException("用户信息不能为空");
        }

        // 检查是否已存在相同的微信OpenID
        User existingUser = getUserByWxOpenId(user.getWxOpenId());
        if (existingUser != null) {
            log.info("用户已存在，更新用户信息：{}", user.getWxOpenId());
            return updateUser(existingUser
                .setNickname(user.getNickname())
                .setAvatarUrl(user.getAvatarUrl())
            );
        }

        // 设置默认角色
        user.setRole(UserRoleEnum.USER.getCode());
        userMapper.insert(user);
        log.info("创建新用户：{}", user.getWxOpenId());
        return user;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public User updateUser(User user) {
        if (user == null || StrUtil.isBlank(user.getId())) {
            throw new IllegalArgumentException("用户信息不完整");
        }

        userMapper.updateById(user);
        log.info("更新用户信息：{}", user.getId());
        return user;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public User updateUserRole(String userId, UserRoleEnum role) {
        if (StrUtil.isBlank(userId) || role == null) {
            throw new IllegalArgumentException("用户ID或角色不能为空");
        }

        User user = getUserById(userId);
        if (user == null) {
            throw new AuthorizationException("用户不存在");
        }

        user.setUserRole(role);
        userMapper.updateById(user);
        log.info("更新用户{}角色为：{}", userId, role);
        return user;
    }

    @Override
    public boolean isAdmin(String userId) {
        User user = getUserById(userId);
        return user != null && (
            user.getUserRole() == UserRoleEnum.ADMIN || 
            user.getUserRole() == UserRoleEnum.SUPER_ADMIN
        );
    }

    @Override
    public boolean isSuperAdmin(String userId) {
        User user = getUserById(userId);
        return user != null && user.getUserRole() == UserRoleEnum.SUPER_ADMIN;
    }

    @Override
    public String generateUserToken(User user) {
        // Token过期时间为30天
        Date expiration = Date.from(
            LocalDateTime.now().plusDays(30)
                .atZone(ZoneId.systemDefault())
                .toInstant()
        );

        return Jwts.builder()
            .setSubject(user.getId())
            .claim("role", user.getRole())
            .setIssuedAt(new Date())
            .setExpiration(expiration)
            .signWith(jwtSecretKey, SignatureAlgorithm.HS256)
            .compact();
    }

    @Override
    public String validateUserToken(String token) {
        try {
            return Jwts.parserBuilder()
                .setSigningKey(jwtSecretKey)
                .build()
                .parseClaimsJws(token)
                .getBody()
                .getSubject();
        } catch (Exception e) {
            log.error("Token验证失败", e);
            throw new AuthorizationException("Token验证失败");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public User completeProfile(String userId, UserProfileDTO profileDTO) {
        // 检查用户是否存在
        User user = getUserById(userId);
        if (user == null) {
            throw new AuthorizationException("用户不存在");
        }

        // 检查手机号是否已被其他用户使用
        if (StrUtil.isNotBlank(profileDTO.getPhone())) {
            LambdaQueryWrapper<User> phoneQuery = new LambdaQueryWrapper<>();
            phoneQuery.eq(User::getPhone, profileDTO.getPhone())
                      .ne(User::getId, userId);
            if (userMapper.selectCount(phoneQuery) > 0) {
                throw new AuthorizationException("手机号已被其他用户使用");
            }
        }

        // 检查邮箱是否已被其他用户使用
        if (StrUtil.isNotBlank(profileDTO.getEmail())) {
            LambdaQueryWrapper<User> emailQuery = new LambdaQueryWrapper<>();
            emailQuery.eq(User::getEmail, profileDTO.getEmail())
                      .ne(User::getId, userId);
            if (userMapper.selectCount(emailQuery) > 0) {
                throw new AuthorizationException("邮箱已被其他用户使用");
            }
        }

        // 更新用户信息
        BeanUtils.copyProperties(profileDTO, user, "id", "wxOpenId", "role");
        user.setUpdateTime(LocalDateTime.now());
        userMapper.updateById(user);

        log.info("用户{}完善个人信息", userId);
        return user;
    }

    @Override
    public boolean isProfileComplete(String userId) {
        User user = getUserById(userId);
        if (user == null) {
            return false;
        }

        // 判断关键信息是否完整
        return StrUtil.isNotBlank(user.getNickname()) &&
               StrUtil.isNotBlank(user.getAvatarUrl()) &&
               (StrUtil.isNotBlank(user.getPhone()) || StrUtil.isNotBlank(user.getEmail()));
    }

    @Override
    public User getUserDetails(String userId) {
        User user = getUserById(userId);
        if (user == null) {
            throw new AuthorizationException("用户不存在");
        }
        return user;
    }
} 